package org.ushio.speech_module.speech.audio;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.ushio.common_module.config.annotation.Loggable;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;

/**
 * @author 陈红
 */
@Service
public class UserRecordingService {

    public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final Logger logger = LoggerFactory.getLogger(UserRecordingService.class);

    @Autowired
    private UserRecordingMapper userRecordingMapper;

    @Value("${python.service.url}")
    private String pythonServiceUrl;

    /**
     * 识别并保存用户的录音
     *
     * @param file 用户上传的音频文件
     * @param referenceText 参考文本
     * @param userId 用户ID
     * @param sentenceId 句子ID
     * @param chapterId 章节ID
     * @return 识别结果
     * @throws IOException 如果文件读取失败
     */
    @Transactional(rollbackFor = {IOException.class, HttpClientErrorException.class, HttpServerErrorException.class})
    @Loggable("用户录音")
    public String recognizeAndSaveRecording(MultipartFile file, String referenceText, Long userId, Long sentenceId, Long chapterId) throws IOException {
        logger.info("Starting recognizeAndSaveRecording with file: {}, referenceText: {}, userId: {}, sentenceId: {}, chapterId: {}",
                file.getOriginalFilename(), referenceText, userId, sentenceId, chapterId);

        // 创建 RestTemplate
        RestTemplate restTemplate = new RestTemplate();

        // 创建 multipart 请求
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("file", new ByteArrayResource(file.getBytes()) {
            @Override
            public String getFilename() {
                return file.getOriginalFilename();
            }
        });
        body.add("reference_text", referenceText);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);

        try {
            // 发送请求到 Python Flask 服务
            ResponseEntity<String> response = restTemplate.exchange(pythonServiceUrl + "/recognize", HttpMethod.POST, entity, String.class);
            logger.info("Flask Response: {}", response.getBody());

            // 解析识别结果
            RecognitionResponse recognitionResponse = OBJECT_MAPPER.readValue(response.getBody(), RecognitionResponse.class);

            // 创建 UserRecording 对象
            UserRecording userRecording = new UserRecording();
            userRecording.setUserId(userId);
            userRecording.setSentenceId(sentenceId);
            userRecording.setChapterId(chapterId);
            userRecording.setRecordingBlob(file.getBytes());
            userRecording.setRecognitionResult(recognitionResponse.getFeedback());
            userRecording.setScore(recognitionResponse.getScore());
            userRecording.setTextMatchScore(recognitionResponse.getTextMatchScore());
            userRecording.setPitchScore(recognitionResponse.getPitchScore());
            userRecording.setIntensityScore(recognitionResponse.getIntensityScore());
            userRecording.setSpeechRateScore(recognitionResponse.getSpeechRateScore());
            userRecording.setCreatedAt(new Timestamp(System.currentTimeMillis()));
            userRecording.setUpdatedAt(new Timestamp(System.currentTimeMillis()));

            // 获取序列值
            Long recordingId = userRecordingMapper.getRecordingSequence();
            userRecording.setRecordingId(recordingId);

            // 检查是否已经存在该用户的录音记录
            UserRecording existingRecording = userRecordingMapper.getUserRecordingByUserIdAndSentenceId(userId, sentenceId);
            logger.info("Existing UserRecording: {}", existingRecording);

            if (existingRecording != null) {
                // 更新现有记录
                userRecording.setRecordingId(existingRecording.getRecordingId());
                userRecordingMapper.updateUserRecording(userRecording);
                logger.info("Updated UserRecording: {}", userRecording);
            } else {
                // 插入新记录
                int rowsAffected = userRecordingMapper.insertUserRecording(userRecording);
                if (rowsAffected > 0) {
                    logger.info("Inserted UserRecording: {}", userRecording);
                } else {
                    logger.error("Failed to insert UserRecording.");
                    throw new RuntimeException("Failed to insert UserRecording.");
                }
            }

            // 返回识别结果
            return recognitionResponse.getFeedback();
        } catch (HttpClientErrorException e) {
            // 处理 4xx 错误
            logger.error("Client error occurred: {}", e.getMessage(), e);
            throw new RuntimeException("Client error occurred while calling Flask service", e);
        } catch (HttpServerErrorException e) {
            // 处理 5xx 错误
            logger.error("Server error occurred: {}", e.getMessage(), e);
            throw new RuntimeException("Error occurred while calling Flask service", e);
        } catch (Exception e) {
            // 处理其他异常
            logger.error("Unexpected error occurred: {}", e.getMessage(), e);
            throw new RuntimeException("Unexpected error occurred while calling Flask service", e);
        } finally {
            logger.info("处理并保存录音成功！");
        }
    }

    /**
     * 根据用户ID和句子ID获取用户的录音记录
     *
     * @param userId 用户ID
     * @param sentenceId 句子ID
     * @return 用户录音记录
     */
    public UserRecording getUserRecordingByUserIdAndSentenceId(Long userId, Long sentenceId) {
        return userRecordingMapper.getUserRecordingByUserIdAndSentenceId(userId, sentenceId);
    }

    /**
     * 根据用户ID获取用户的录音记录
     *
     * @param userId 用户ID
     * @return 用户录音记录列表
     */
    public List<UserRecording> getUserRecordingByUserId(Long userId) {
        return userRecordingMapper.getUserRecordingByUserId(userId);
    }

    /**
     * 根据章节ID获取用户的录音记录
     *
     * @param chapterId 章节ID
     * @return 用户录音记录列表
     */
    public List<UserRecording> getUserRecordingsByChapterId(Long chapterId) {
        return userRecordingMapper.getUserRecordingsByChapterId(chapterId);
    }

    /**
     * 根据用户ID和章节ID获取用户的录音记录
     *
     * @param userId 用户ID
     * @param chapterId 章节ID
     * @return 用户录音记录列表
     */
    @Transactional(readOnly = true)
    public List<UserRecording> getUserRecordingByUserIdAndChapterId(Long userId, Long chapterId) {
        logger.info("Starting getUserRecordingByUserIdAndChapterId with userId: {}, chapterId: {}", userId, chapterId);

        Map<String, Long> params = Map.of("userId", userId, "chapterId", chapterId);
        List<UserRecording> userRecordings = userRecordingMapper.getUserRecordingByUserIdAndChapterId(params);
        logger.info("Fetched UserRecordings: {}", userRecordings);

        return userRecordings;
    }

    /**
     * 用于解析 Flask 服务返回的 JSON 响应
     */
    @Getter
    private static class RecognitionResponse {
        private String feedback;
        private Double score;
        private Double textMatchScore;
        private Double pitchScore;
        private Double intensityScore;
        private Double speechRateScore;
    }
}